package at.pimpmypipe.filter;

import java.io.StreamCorruptedException;
import java.security.InvalidParameterException;

import at.pimpmypipe.interfaces.IOable;
import at.pimpmypipe.interfaces.Readable;
import at.pimpmypipe.interfaces.Writeable;

public abstract class AbstractFilter<in, out> implements IOable<in, out>, Runnable {
	
    private Readable<in> _input = null;
    private Writeable<out> _output = null;
    
    public static Object ENDING_SIGNAL = null;
    
    public AbstractFilter() {
    	
    }
    
    public AbstractFilter(Readable<in> input) throws InvalidParameterException{
        if (input == null) {
            throw new InvalidParameterException("input can't be null!");
        }
        _input = input;
    }
    
    public AbstractFilter(Writeable<out> output)throws InvalidParameterException{
        if (output == null) {
            throw new InvalidParameterException("output can't be null!");
        }
        _output = output;
    }
    
    public AbstractFilter(Readable<in> input, Writeable<out> output)throws InvalidParameterException{
        if (input == null) {
            throw new InvalidParameterException("input can't be null!");
        } else if (output == null) {
            throw new InvalidParameterException("output can't be null!");
        }
        _input = input;
        _output = output;
    }
    
    protected void writeOutput(out value) throws StreamCorruptedException{
        if (_output != null) {
            if (value == ENDING_SIGNAL) {
            	beforeSendingEndingSignal();
            }
            _output.write(value);
        } else {
            throw new StreamCorruptedException("output is null");
        }
    }
    
    protected in readInput() throws StreamCorruptedException{
        if (_input != null) {
            return _input.read();
        } else {
            throw new StreamCorruptedException("input is null");
        }
    }
    
    /**
     * send a signal, that the end of the stream has been reached
     */
    protected void sendEndSignal() throws StreamCorruptedException{
        writeOutput(null);
    }
    
    /**
     * derived class may override this, if they are interested in 
     * getting informed before the ending-signal is sended
     */
    protected void beforeSendingEndingSignal() throws StreamCorruptedException {}

	public void setInput(Readable<in> input) {
		_input = input;
	}

	public void setOutput(Writeable<out> output) {
		_output = output;
	}
}
